#include "GetArg.h"

// -*-C++-*-------------------------------------------------------------------
//
// Author: Ulrike Hoefer
//
// Date: July 98
//
// Name of the method: searchValueOfOption
//
// Description: evaluate an argv and define the input and the
// option according to argv
//
// ---------------------------------------------------------------------------

void searchValueOfOption( char option[80], string &input, char *argv )
{
  // if there's an option, get this option:
  if( argv[0] == '-' ) 
    {
      // if the next character is a "-", you know, that the option
      // is a word, otherwise it is one character:
      if( argv[1] == '-' ) 
	{
	  int k = 0;
	  while( argv[k] != '\0' )
	   { 
	     option[k] = argv[k+1]; 
	     k++;
	   }
	  input = "";
	} // if( argv[1] == '-' ) 
      else
	{ 
	  option[0] = argv[1]; 
	  option[1] = '\0';
	  // if the option contains only one character, check, if
	  // the value is appended directly:
	  if( argv[2] != '\0' )
	    {
	      char tempName[80];

	      int k = 1;
	      while( argv[k] != '\0' )
		{ 
		  tempName[k-1] = argv[k+1];
		  k++; 
		}
	      input = tempName;
	    }
	  else
	    { input = ""; }
	} // else (if(argv[1]=='-') ) 
    } // if( argv[0] == '-' )
  else
    { input = argv; }
}



// -*-C++-*-------------------------------------------------------------------
//
// Author: Ulrike Hoefer
//
// Date: July 98
//
// Name of the method: getArg
//
// Description: interprets the inputs of the commando line, assigne a
// variable a commando line input
//
// Precondition: option of the variable
//
// Postcondition: the value of the variable
// the value can be
// - a string
// - a integer
// - a long integer
// - a float
// - a double
// - a vector of integers
// - a vector of doubles
// 
// Errors: if an option is chosen several times, an argument is
// defined severals times or if an option is chosen but no argument is
// given
//
// ---------------------------------------------------------------------------

// value = string:
bool getArg( const char *givenOption, string &value, 
	     const int &argc, char *argv[], string defaultValue,
	     bool justOption )
{
  int countOption = 0, countValue = 0;
  string input;
  char option[80];

  option[0] = '\0';
  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, input, argv[i] );
      // if there's an option, get this option:
      if( argv[i][0] == '-' ) 
	{
	  if( strcmp(givenOption, option) == 0 )
	    { countOption++; }
	  else
	    { continue; }
 	} // if( argv[i][0] == '-' )
      // now interpret the input:
      if( input != "" )
	{
	  if( strcmp(givenOption, option) == 0 )
	    { 
	      countValue++;
	      value = input;
	    }
	  else
	    { continue; }
	} // if( input != "" )
    } // for( i < argc )

  // if an option is selected several times:
  if( countOption > 1 )
    {
#ifndef CONTINUE
      cerr << "You have given too often the option \"" 
	   << givenOption << "\"" << endl;
      ERROR( "Too many options", exception); 
#else
      return false;
#endif
    }
  if( countValue > 1 )
    {
#ifndef CONTINUE
      cerr << "You have given too many input of the option \"" 
	   << givenOption << "\"" << endl;
      ERROR( "Too many options", exception); 
#else
      return false;
#endif
    }
  if( justOption == false )
    { 
      if( (countOption==1) && (countValue==0) )
	{
#ifndef CONTINUE
	  cerr << "You have chosen the option \"" << givenOption 
	       << "\" but havn't specified the value!" << endl;
	  ERROR( "Missing value", exception); 
#else
	  return false;
#endif
	} // if( (countOption==1) && (countValue==0) &&)
      // check, if value is defined:
      if( value == "" )
	{ value = defaultValue; }
#ifdef PATH
      else
	{
	  // check, if value is just the path (last character of value
	  // is "/"):
	  if( value[value.size()-1] == '/' )
	    { value = value + defaultValue; }
	}
#endif
    } // if( justOption == false )
  else
    {
      if( (countOption==1) && (countValue==0) && (value=="") )
	{ value = defaultValue; }
      if( (countOption==0) && (countValue==0) )
	{ value = ""; }
#ifdef PATH
      // check, if value is just the path (last character of value
      // is "/"):
      if( value[value.size()-1] == '/' )
	{ value = value + defaultValue; }
#endif	  
    } // else (if(justOption==false))
  return true;
}

// value = integer:
bool getArg( const char *givenOption, int &value, 
	     const int &argc, char *argv[], int defaultValue )
{
  bool result;
  string tempInt;
  
  value = defaultValue;
  result = getArg( givenOption, tempInt, argc, argv );
  if( tempInt != "" )
    { value = stoi( tempInt ); }
  return result;
}

// value = unsigned integer:
bool getArg( const char *givenOption, unsigned int &value, 
	     const int &argc, char *argv[], unsigned int defaultValue )
{
  bool result;
  string tempInt;
  
  value = defaultValue;
  result = getArg( givenOption, tempInt, argc, argv );
  if( tempInt != "" )
    { value = stoui( tempInt ); }
  return result;
}


// value = long integer:
bool getArg( const char *givenOption, long &value, 
	     const int &argc, char *argv[], long defaultValue )
{
  bool result;
  string tempInt;
  
  value = defaultValue;
  result = getArg( givenOption, tempInt, argc, argv );
  if( tempInt != "" )
    { value = stol( tempInt ); }
  return result;
}

// value = float:
bool getArg( const char *givenOption, float &value, 
	     const int &argc, char *argv[], float defaultValue )
{
  bool result;
  string tempInt;
  
  value = defaultValue;
  result = getArg( givenOption, tempInt, argc, argv );
  if( tempInt != "" )
    { value = stof( tempInt ); }
  return result;
}

// value = double:
bool getArg( const char *givenOption, double &value, 
	     const int &argc, char *argv[], double defaultValue )
{
  bool result;
  string tempInt;
  
  value = defaultValue;
  result = getArg( givenOption, tempInt, argc, argv );
  if( tempInt != "" )
    { value = stod( tempInt ); }
  return result;
}


// value = vector of integer:
bool getArg( const char *givenOption, vector<int> &value, 
	     const int &argc, char *argv[], bool twiceSameNumber )
{
  int countOption = 0;
  string input;
  char option[80];

  option[0] = '\0';
  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, input, argv[i] );
      // if there's an option, get this option:
      if( argv[i][0] == '-' ) 
	{
	  if( strcmp(givenOption, option) == 0 )
	    { countOption++; }
	  else
	    { continue; }
 	} // if( argv[i][0] == '-' )
      // now interpret the input:
      if( input != "" )
	{
	  if( twiceSameNumber == true )
	    {
	      // take each number:
	      if( strcmp(givenOption, option) == 0 )
		{ value.push_back( stoi( input ) ); }
	      else
		{ continue; }
	    } // if( twiceSameNumber == true )
	  else
	    {
	      // take each number, if not yet taken:
	      if( strcmp(givenOption, option) == 0 )
		{ 
		  bool alreadyAdded = false;
		  for( unsigned int i = 0; i < value.size(); i++ )
		    {
		      if( stoi( input ) == value[i] )
			{
			  alreadyAdded = true;
			  break;
			}
		    }
		  if( alreadyAdded == false )
		    { value.push_back( stoi( input ) ); }
		} // if( strcmp(givenOption, option) == 0 )
	      else
		{ continue; }
	    } // else ( if(twiceSameNumber==true) )
	} // if( input != "" )
    } // for( i < argc )
  // if an option is selected but not specified:
  if( (countOption>0) && (value.size()==0) )
    {
#ifndef CONTINUE
      cerr << "You have chosen the option \"" 
	   << givenOption << "\" but haven't specified the value!" << endl;
      ERROR( "Missing value(s)", exception); 
#else
      return false;
#endif
    }
  return true;
}

// value = vector of unsigned integer:
bool getArg( const char *givenOption, vector<unsigned int> &value, 
	     const int &argc, char *argv[], bool twiceSameNumber )
{
  int countOption = 0;
  string input;
  char option[80];

  option[0] = '\0';
  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, input, argv[i] );
      // if there's an option, get this option:
      if( argv[i][0] == '-' ) 
	{
	  if( strcmp(givenOption, option) == 0 )
	    { countOption++; }
	  else
	    { continue; }
 	} // if( argv[i][0] == '-' )
      // now interpret the input:
      if( input != "" )
	{
	  if( twiceSameNumber == true )
	    {
	      // take each number:
	      if( strcmp(givenOption, option) == 0 )
		{ value.push_back( stoui( input ) ); }
	      else
		{ continue; }
	    } // if( twiceSameNumber == true )
	  else
	    {
	      // take each number, if not yet taken:
	      if( strcmp(givenOption, option) == 0 )
		{ 
		  bool alreadyAdded = false;
		  for( unsigned int i = 0; i < value.size(); i++ )
		    {
		      if( stoui( input ) == value[i] )
			{
			  alreadyAdded = true;
			  break;
			}
		    }
		  if( alreadyAdded == false )
		    { value.push_back( stoui( input ) ); }
		} // if( strcmp(givenOption, option) == 0 )
	      else
		{ continue; }
	    } // else ( if(twiceSameNumber==true) )
	} // if( input != "" )
    } // for( i < argc )
  // if an option is selected but not specified:
  if( (countOption>0) && (value.size()==0) )
    {
#ifndef CONTINUE
      cerr << "You have chosen the option \"" 
	   << givenOption << "\" but haven't specified the value!" << endl;
      ERROR( "Missing value(s)", exception); 
#else
      return false;
#endif
    }
  return true;
}

// value = vector of double:
bool getArg( const char *givenOption, vector<double> &value, 
	     const int &argc, char *argv[], bool twiceSameNumber )
{
  int countOption = 0;
  string input;
  char option[80];

  option[0] = '\0';
  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, input, argv[i] );
      // if there's an option, get this option:
      if( argv[i][0] == '-' ) 
	{
	  if( strcmp(givenOption, option) == 0 )
	    { countOption++; }
	  else
	    { continue; }
 	} // if( argv[i][0] == '-' )
      // now interpret the input:
      if( input != "" )
	{
	  if( twiceSameNumber == true )
	    {
	      // take each number:
	      if( strcmp(givenOption, option) == 0 )
		{ value.push_back( stod( input ) ); }
	      else
		{ continue; }
	    } // if( twiceSameNumber == true )
	  else
	    {
	      // take each number, if not yet taken:
	      if( strcmp(givenOption, option) == 0 )
		{ 
		  bool alreadyAdded = false;
		  for( unsigned int i = 0; i < value.size(); i++ )
		    {
		      if( stod( input ) == value[i] )
			{
			  alreadyAdded = true;
			  break;
			}
		    }
		  if( alreadyAdded == false )
		    { value.push_back( stod( input ) ); }
		} // if( strcmp(givenOption, option) == 0 )
	      else
		{ continue; }
	    } // else ( if(twiceSameNumber==true) )
	} // if( input != "" )
    } // for( i < argc )
  // if an option is selected but not specified:
  if( (countOption>0) && (value.size()==0) )
    {
#ifndef CONTINUE
      cerr << "You have chosen the option \"" 
	   << givenOption << "\" but haven't specified the value!" << endl;
      ERROR( "Missing value(s)", exception); 
#else
      return false;
#endif
    }
  return true;
}

// value = vector of strings:
bool getArg( const char *givenOption, vector<string> &value, 
	     const int &argc, char *argv[], bool twiceSameNumber )
{
  int countOption = 0;
  string input;
  char option[80];

  option[0] = '\0';
  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, input, argv[i] );
      // if there's an option, get this option:
      if( argv[i][0] == '-' ) 
	{
	  if( strcmp(givenOption, option) == 0 )
	    { countOption++; }
	  else
	    { continue; }
 	} // if( argv[i][0] == '-' )
      // now interpret the input:
      if( input != "" )
	{
	  if( twiceSameNumber == true )
	    {
	      // take each number:
	      if( strcmp(givenOption, option) == 0 )
		{ value.push_back( input ); }
	      else
		{ continue; }
	    } // if( twiceSameNumber == true )
	  else
	    {
	      // take each number, if not yet taken:
	      if( strcmp(givenOption, option) == 0 )
		{ 
		  bool alreadyAdded = false;
		  for( unsigned int i = 0; i < value.size(); i++ )
		    {
		      if( input.compare( value[i] ) == 0 )
			{
			  alreadyAdded = true;
			  break;
			}
		    }
		  if( alreadyAdded == false )
		    { value.push_back( input ); }
		} // if( strcmp(givenOption, option) == 0 )
	      else
		{ continue; }
	    } // else ( if(twiceSameNumber==true) )
	} // if( input != "" )
    } // for( i < argc )
  // if an option is selected but not specified:
  if( (countOption>0) && (value.size()==0) )
    {
#ifndef CONTINUE
      cerr << "You have chosen the option \"" 
	   << givenOption << "\" but haven't specified the value!" << endl;
      ERROR( "Missing value(s)", exception); 
#else
      return false;
#endif
    }
  return true;
}


// -*-C++-*-------------------------------------------------------------------
//
// Author: Ulrike Hoefer
//
// Date: July 98
//
// Name of the method: getArgs
//
// Description: interprets the inputs of the commando line, assigne a
// variable a commando line input, several words will be put in one
// string
//
// Precondition: option of the variable
//
// Postcondition: the value of the variable
// 
//
// ---------------------------------------------------------------------------

bool getArgs( const char *givenOption, string &value, 
	      const int &argc, char *argv[], string defaultValue )
{
  int countOption = 0;
  char option[80];
  string input;

  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, input, argv[i] );
      if( input != "" )
	{
	  if( strcmp(givenOption, option) == 0 )
	    { value = value + " " + input; }
	  else
	    { continue; }
	} // if( input != "" )
    } // for( i < argc )
  // if an option is selected but not specified:
  if( (countOption>0) && (value.size()==0) )
    {
#ifndef CONTINUE
      cerr << "You have chosen the option \"" 
	   << givenOption << "\" but haven't specified the value!" << endl;
      ERROR( "Missing value(s)", exception); 
#else
  return false;
#endif
    }
  if( value.size() == 0 )
    { value = defaultValue; }
  return true;
}


// -*-C++-*-------------------------------------------------------------------
//
// Author: Ulrike Hoefer
//
// Date: July 98
//
// Name of the method: getArg
//
// Decription: check, if an option is chosen
//
// ---------------------------------------------------------------------------

bool getArg( const char *givenOption, const int &argc, char *argv[],
	     string text, bool stop )
{
  char option[80];
  string str;
  
  option[0] = '\0';
  for( int i = 1; i < argc; i++ )
    {
      searchValueOfOption( option, str, argv[i] );
      if( strcmp(givenOption, option) == 0 )
 	{ 
	  if( text != "" )
	    { cout << text << endl; }
	  if( stop == true )
	    { exit(0); }
	  return true;
 	}
    } // for( i < argc )
  return false; // didn't find option
}


// -*-C++-*-------------------------------------------------------------------
//
// Author: Ulrike Hoefer
//
// Date: July 98
//
// Name of the method: checkArg
//
// Description: check, if there are chosen wrong options, if an
// unknown option is chosen, then error, if you give a text, then show
// this text
//
// ---------------------------------------------------------------------------

bool checkArg( const int &argc, char *argv[], int optionNumber ... )
{
  bool rightOption = false;  
  char option[80];
  string str;
  va_list listOfOptions;

  option[0] = '\0';
  if( argc <= 1 )
    { return true; }
  // check, if the first input is an option:
  if( argv[1][0] !=  '-' ) 
    {
#ifndef CONTINUE 
      ERROR( "First input isn't an option", exception); 
#else
      return false;
#endif 
    }
  for( int i = 1; i < argc; i++ )
     {
       rightOption = false;
       searchValueOfOption( option, str, argv[i] );
       // define the listOfOptions:
       va_start( listOfOptions, optionNumber );
       // every given Options is a *char, get all givenOptions:
       for( int i = 0; i < optionNumber; i++ )
	 {
	   char *givenOption = va_arg( listOfOptions, char* );
	   if( givenOption == 0 )
	     { break; }
	   if( strcmp(givenOption, option) == 0 )
	     { 
	       rightOption = true;
	       break; // go to the next option
	     }	   
	 } // for( i < optionNumber )
       // end of the list:
       va_end( listOfOptions );
       if( rightOption == false )
	 {
#ifndef CONTINUE 
	   cerr << "\"" << option << "\" is a wrong option" << endl;
	   ERROR( "Wrong option", exception); 	   
#else
	   return false;
#endif 
	 } // if( rightOption == false )
     } // for( i < argc )
  return true;
}

// show text:
bool checkArg( string text, const int &argc, char *argv[], 
	       int optionNumber ... )
{
  bool rightOption = false;  
  char option[80];
  string str;
  va_list listOfOptions;

  option[0] = '\0';
  if( argc <= 1 )
    { return true; }
  // check, if the first input is an option:
  if( argv[1][0] !=  '-' ) 
    {
#ifndef CONTINUE 
      cerr << text << endl;
      ERROR( "First input isn't an option", exception); 
#else
      return false;
#endif 
    }
  for( int i = 1; i < argc; i++ )
     {
       rightOption = false;
       searchValueOfOption( option, str, argv[i] );
       // define the listOfOptions:
       va_start( listOfOptions, optionNumber );
       // every given Options is a *char, get all givenOptions:
       for( int i = 0; i < optionNumber; i++ )
	 {
	   char *givenOption = va_arg( listOfOptions, char* );
	   if( givenOption == 0 )
	     { break; }
	   if( strcmp(givenOption, option) == 0 )
	     { 
	       rightOption = true;
	       break; // go to the next option
	     }	   
	 } // for( i < optionNumber )
       // end of the list:
       va_end( listOfOptions );
       if( rightOption == false )
	 {
#ifndef CONTINUE 
	   cerr << "\"" << option << "\" is a wrong option" << endl
		<< text << endl;
	   ERROR( "Wrong option", exception); 	   
#else
	   return false;
#endif 
	 } // if( rightOption == false )
     } // for( i < argc )
  return true;
}


void getOption(double& param, char* optName, int nArgs, char* argv[], 
bool verbose)
{
  double tmp = -100000.0;
  getArg(optName, tmp, nArgs, argv, -100000.0);
  if (tmp > -100000.0)
    {
      param = tmp;
      if (verbose)
	cout << optName << " = " << tmp << "\n";
    }
}

void getOption(unsigned int& param, char* optName, int nArgs, char* argv[], 
bool verbose)
{
  unsigned int tmp = INT_MAX;
  getArg(optName, tmp, nArgs, argv, INT_MAX);
  if (tmp != INT_MAX)
    {
      param = tmp;
      if (verbose)
	cout << optName << " = " << tmp << "\n";
    }
}

void getOption(float& param, char* optName, int nArgs, char* argv[], 
bool verbose)
{
  float tmp = -100000.0;
  getArg(optName, tmp, nArgs, argv, -100000.0);
  if (tmp > -100000.0)
    {
      param = tmp;
      if (verbose)
	cout << optName << " = " << tmp << "\n";
    }
}

bool getOption(char* optName, int nArgs, char* argv[], 
bool verbose)
{
  bool tmp = getArg( optName, nArgs, argv);
  if ((tmp) && (verbose))
    cout << optName << "\n";
  return tmp;
}
